"""
监控数据WebSocket消费者
实现实时监控数据推送
"""
import json
import asyncio
import logging
from channels.generic.websocket import AsyncWebsocketConsumer
from channels.db import database_sync_to_async
from django.contrib.auth.models import AnonymousUser
from django.utils import timezone
from .models import ZabbixServer, MonitoringHost, MonitoringAlert
from .utils.zabbix_api import ZabbixAPIManager

logger = logging.getLogger(__name__)


class MonitoringConsumer(AsyncWebsocketConsumer):
    """监控数据WebSocket消费者"""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.room_group_name = 'monitoring_updates'
        self.update_task = None
        self.is_authenticated = False

    async def connect(self):
        """WebSocket连接"""
        # 检查用户认证
        user = self.scope.get('user')
        if isinstance(user, AnonymousUser) or not user or not user.is_authenticated:
            logger.warning(f"WebSocket连接被拒绝: 用户未认证 - {user}")
            await self.close()
            return

        self.is_authenticated = True
        logger.info(f"WebSocket连接认证成功: {user.username}")

        # 加入监控更新组
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        await self.accept()

        # 发送初始数据
        await self.send_initial_data()

        # 启用定期更新任务，提供实时监控
        self.update_task = asyncio.create_task(self.periodic_update())

        logger.info(f"监控WebSocket连接建立: {user.username}")

    async def disconnect(self, close_code):
        """WebSocket断开连接"""
        if self.is_authenticated:
            # 停止更新任务
            if self.update_task:
                self.update_task.cancel()

            # 离开监控更新组
            await self.channel_layer.group_discard(
                self.room_group_name,
                self.channel_name
            )

            logger.info(f"监控WebSocket连接断开: {close_code}")

    async def receive(self, text_data):
        """接收WebSocket消息"""
        try:
            data = json.loads(text_data)
            message_type = data.get('type')

            if message_type == 'request_update':
                # 客户端请求立即更新
                await self.send_monitoring_data()
            elif message_type == 'subscribe_server':
                # 订阅特定服务器的数据
                server_id = data.get('server_id')
                await self.send_server_data(server_id)
            elif message_type == 'ping':
                # 心跳检测
                await self.send(text_data=json.dumps({
                    'type': 'pong',
                    'timestamp': timezone.now().isoformat()
                }))

        except json.JSONDecodeError:
            logger.error("WebSocket接收到无效JSON数据")
        except Exception as e:
            logger.error(f"WebSocket消息处理失败: {e}")

    async def send_initial_data(self):
        """发送初始数据"""
        try:
            # 获取监控概览数据
            overview_data = await self.get_monitoring_overview()

            await self.send(text_data=json.dumps({
                'type': 'initial_data',
                'data': overview_data,
                'timestamp': timezone.now().isoformat()
            }))

        except Exception as e:
            logger.error(f"发送初始数据失败: {e}")

    async def periodic_update(self):
        """定期更新监控数据"""
        try:
            while True:
                await asyncio.sleep(60)  # 改为每60秒更新一次，减少频率
                await self.send_monitoring_data()
        except asyncio.CancelledError:
            logger.info("定期更新任务已取消")
        except Exception as e:
            logger.error(f"定期更新失败: {e}")

    async def send_monitoring_data(self):
        """发送监控数据"""
        try:
            # 获取最新的监控数据
            overview_data = await self.get_monitoring_overview()
            host_status_data = await self.get_host_status()
            alert_data = await self.get_recent_alerts()

            await self.send(text_data=json.dumps({
                'type': 'monitoring_update',
                'data': {
                    'overview': overview_data,
                    'host_status': host_status_data,
                    'alerts': alert_data
                },
                'timestamp': timezone.now().isoformat()
            }))

        except Exception as e:
            logger.error(f"发送监控数据失败: {e}")

    async def send_server_data(self, server_id):
        """发送特定服务器的数据"""
        try:
            if not server_id:
                return

            server_data = await self.get_server_data(server_id)

            await self.send(text_data=json.dumps({
                'type': 'server_data',
                'server_id': server_id,
                'data': server_data,
                'timestamp': timezone.now().isoformat()
            }))

        except Exception as e:
            logger.error(f"发送服务器数据失败: {e}")

    @database_sync_to_async
    def get_monitoring_overview(self):
        """获取监控概览数据"""
        try:
            # 统计数据
            total_zabbix_servers = ZabbixServer.objects.filter(is_active=True).count()
            total_grafana_servers = 0  # Grafana功能已移除
            total_monitored_hosts = MonitoringHost.objects.filter(monitoring_status='monitoring').count()
            total_active_alerts = MonitoringAlert.objects.filter(status='active').count()

            # 连接状态统计
            connected_zabbix = ZabbixServer.objects.filter(
                is_active=True, connection_status='connected'
            ).count()
            connected_grafana = 0  # Grafana功能已移除

            # 告警分级统计
            from django.db.models import Count
            alert_stats = MonitoringAlert.objects.filter(status='active').values('severity').annotate(
                count=Count('id')
            )

            alert_severity_stats = {'high': 0, 'medium': 0, 'low': 0}
            for alert in alert_stats:
                if alert['severity'] in alert_severity_stats:
                    alert_severity_stats[alert['severity']] = alert['count']

            # 主机状态统计
            host_status_stats = MonitoringHost.objects.values('monitoring_status').annotate(
                count=Count('id')
            )

            return {
                'servers': {
                    'zabbix_total': total_zabbix_servers,
                    'zabbix_connected': connected_zabbix,
                    'grafana_total': total_grafana_servers,
                    'grafana_connected': connected_grafana
                },
                'monitoring': {
                    'total_hosts': total_monitored_hosts,
                    'active_alerts': total_active_alerts,
                    'alert_severity': alert_severity_stats,
                    'host_status': list(host_status_stats)
                }
            }

        except Exception as e:
            logger.error(f"获取监控概览数据失败: {e}")
            return {}

    @database_sync_to_async
    def get_host_status(self):
        """获取主机状态数据"""
        try:
            hosts = MonitoringHost.objects.select_related('host', 'zabbix_server').filter(
                monitoring_status='monitoring'
            )[:20]  # 限制返回数量

            host_data = []
            for host in hosts:
                host_data.append({
                    'id': host.id,
                    'hostname': host.host.hostname,
                    'ip_address': host.host.private_ip or host.host.public_ip,
                    'monitoring_status': host.monitoring_status,
                    'availability': host.availability,
                    'last_check_time': host.last_check_time.isoformat() if host.last_check_time else None,
                    'zabbix_server': host.zabbix_server.name
                })

            return host_data

        except Exception as e:
            logger.error(f"获取主机状态数据失败: {e}")
            return []

    @database_sync_to_async
    def get_recent_alerts(self):
        """获取最近的告警数据"""
        try:
            alerts = MonitoringAlert.objects.select_related('host', 'zabbix_server').filter(
                status='active'
            ).order_by('-created_at')[:10]  # 最近10条告警

            alert_data = []
            for alert in alerts:
                alert_data.append({
                    'id': alert.id,
                    'title': alert.title,
                    'description': alert.description,
                    'severity': alert.severity,
                    'status': alert.status,
                    'hostname': alert.host.hostname if alert.host else None,
                    'created_at': alert.created_at.isoformat(),
                    'zabbix_server': alert.zabbix_server.name
                })

            return alert_data

        except Exception as e:
            logger.error(f"获取告警数据失败: {e}")
            return []

    @database_sync_to_async
    def get_server_data(self, server_id):
        """获取特定服务器的数据"""
        try:
            server = ZabbixServer.objects.get(id=server_id, is_active=True)

            # 获取该服务器的主机数量
            host_count = MonitoringHost.objects.filter(zabbix_server=server).count()

            # 获取该服务器的告警数量
            alert_count = MonitoringAlert.objects.filter(
                zabbix_server=server, status='active'
            ).count()

            return {
                'server_info': {
                    'id': server.id,
                    'name': server.name,
                    'url': server.url,
                    'connection_status': server.connection_status,
                    'last_check_time': server.last_check_time.isoformat() if server.last_check_time else None
                },
                'statistics': {
                    'total_hosts': server.total_hosts,
                    'total_items': server.total_items,
                    'total_triggers': server.total_triggers,
                    'monitored_hosts': host_count,
                    'active_alerts': alert_count
                }
            }

        except ZabbixServer.DoesNotExist:
            return {'error': '服务器不存在'}
        except Exception as e:
            logger.error(f"获取服务器数据失败: {e}")
            return {'error': str(e)}

    # 组消息处理器
    async def monitoring_update(self, event):
        """处理监控更新组消息"""
        await self.send(text_data=json.dumps(event['data']))

    async def alert_notification(self, event):
        """处理告警通知组消息"""
        await self.send(text_data=json.dumps({
            'type': 'alert_notification',
            'data': event['data'],
            'timestamp': timezone.now().isoformat()
        }))
